//#include "stdafx.h"
#include "AndNode.h"

#ifndef M_PI
#define M_PI	3.1415926535897932384626
#endif

bool SortByInstanceScore(NodeInstanceType &p1, NodeInstanceType &p2)
{
	return p1.Score > p2.Score;
}

bool SortBasicNodePairByIndex(BasicNodePairType p1, BasicNodePairType p2)
{
	return p1.LeafNodeIndex < p2.LeafNodeIndex;
}

bool CAndNode::InputFromStream(istream& inStream)
{
	char strTemp[10001];
	if (!(inStream>>strTemp>>ModelID>>Level)) return false;
	if (!(inStream>>parseInfo>>createInfo>>fNeedMakeInstTree>>fNeedRefreshMRFScore)) return false;
	int i, tn;
	if (!(inStream>>tn)) return false;
	children.resize(tn); for ( i = 0; i < tn; ++i ) if (!(inStream>>children[i])) return false;
	if (!(inStream>>tn)) return false;
	fullIndex.resize(tn); for ( i = 0; i < tn; ++i ) if (!(inStream>>fullIndex[i])) return false;
	if (!(inStream>>tn)) return false;
	CenterIndex.resize(tn); for ( i = 0; i < tn; ++i ) if (!(inStream>>CenterIndex[i])) return false;
	if (!(inStream>>tn)) return false;
	ConstrainIndex.resize(tn); for ( i = 0; i < tn; ++i ) if (!(inStream>>ConstrainIndex[i])) return false;
	if (!(inStream>>tn)) return false;
	instances.resize(tn); for ( i = 0; i < tn; ++i ) if (!(instances[i].InputFromStream(inStream))) return false;
	if (!(inStream>>tn)) return false;
	fullInst.resize(tn); for ( i = 0; i < tn; ++i ) if (!(fullInst[i].InputFromStream(inStream))) return false;

	if (!(inStream
		>>BaseAppearanceScore
		>>InstScore_
		))
		return false;
	if (!(inStream>>tn)) return false;
	TripletScore_.resize(tn); for ( i = 0; i < tn; ++i ) if (!(inStream>>TripletScore_[i])) return false;
	if (!(inStream>>tn)) return false;
	ArcScaleScore_.resize(tn); for ( i = 0; i < tn; ++i ) if (!(inStream>>ArcScaleScore_[i])) return false;
	if (!(inStream>>tn)) return false;
	ArcRotScore_.resize(tn); for ( i = 0; i < tn; ++i ) if (!(inStream>>ArcRotScore_[i])) return false;

	if (!(inStream>>NodeType>>leafIndex>>FillMissing)) return false;
	if (!(inStream>>BottomUpTimeCost>>ActiveThres)) return false;
	if (!(inStream>>tn)) return false;
	SearchConstrain.resize(tn); for ( i = 0; i < tn; ++i ) if (!(SearchConstrain[i].InputFromStream(inStream))) return false;

	if (!(inStream
		>>MaxOriDiff
		>>MaxScaleDiff
		>>MaxOri
		>>MinScale
		>>MaxScale
		>>Variance
		//>>MaxLevel
		>>BoundarySize
		>>MaxFullInstCount
		>>MaxInstCount
		>>MinInstCount
		))
		return false;

	return true;
}

void CAndNode::OutputToStream(ostream& outStream) const
{
	outStream
		<<endl<<"::AndNode"
		<<"\t"<<(ModelID<10 ? "0" : "")<<ModelID
		<<"\t"<<Level
		<<endl;
	outStream
		<<"\t"<<parseInfo
		<<"\t"<<createInfo
		<<"\t"<<fNeedMakeInstTree
		<<"\t"<<fNeedRefreshMRFScore
		<<endl;
	int i, tn;
	outStream<<(tn = (int)children.size())<<endl;
	for ( i = 0; i < tn; ++i ) outStream<<"\t"<<children[i];
	outStream<<endl;
	outStream<<(tn = (int)fullIndex.size())<<endl;
	for ( i = 0; i < tn; ++i ) outStream<<"\t"<<fullIndex[i];
	outStream<<endl;
	outStream<<(tn = (int)CenterIndex.size())<<endl;
	for ( i = 0; i < tn; ++i ) outStream<<"\t"<<CenterIndex[i];
	outStream<<endl;
	outStream<<(tn = (int)ConstrainIndex.size())<<endl;
	for ( i = 0; i < tn; ++i ) outStream<<"\t"<<ConstrainIndex[i];
	outStream<<endl;
	outStream<<(tn = (int)instances.size())<<endl;
	for ( i = 0; i < tn; ++i ) { instances[i].OutputToStream(outStream); outStream<<endl; }
	outStream<<(tn = (int)fullInst.size())<<endl;
	for ( i = 0; i < tn; ++i ) { fullInst[i].OutputToStream(outStream); outStream<<endl; }

	outStream<<setprecision(6)
		<<"\t"<<fixed<<BaseAppearanceScore
		<<"\t"<<fixed<<InstScore_
		<<endl;
	outStream<<(tn = (int)TripletScore_.size())<<endl;
	for ( i = 0; i < tn; ++i ) outStream<<setprecision(6)<<"\t"<<fixed<<TripletScore_[i];
	outStream<<endl;
	outStream<<(tn = (int)ArcScaleScore_.size())<<endl;
	for ( i = 0; i < tn; ++i ) outStream<<setprecision(6)<<"\t"<<fixed<<ArcScaleScore_[i];
	outStream<<endl;
	outStream<<(tn = (int)ArcRotScore_.size())<<endl;
	for ( i = 0; i < tn; ++i ) outStream<<setprecision(6)<<"\t"<<fixed<<ArcRotScore_[i];
	outStream<<endl;

	outStream
		<<"\t"<<NodeType
		<<"\t"<<leafIndex
		<<"\t"<<FillMissing
		<<endl;
	outStream<<setprecision(6)
		<<"\t"<<fixed<<BottomUpTimeCost
		<<"\t"<<ActiveThres
		<<endl;
	outStream<<(tn = (int)SearchConstrain.size())<<endl;
	for ( i = 0; i < tn; ++i ) { SearchConstrain[i].OutputToStream(outStream); outStream<<endl; }

	outStream<<setprecision(6)
		<<"\t"<<fixed<<MaxOriDiff
		<<"\t"<<fixed<<MaxScaleDiff
		<<"\t"<<fixed<<MaxOri
		<<"\t"<<fixed<<MinScale
		<<"\t"<<fixed<<MaxScale
		<<"\t"<<fixed<<Variance
		//<<"\t"<<MaxLevel
		<<"\t"<<BoundarySize
		<<"\t"<<MaxFullInstCount
		<<"\t"<<MaxInstCount
		<<"\t"<<MinInstCount
		<<endl;
}

CAndNode::CAndNode(void)
{
	MaxOriDiff				= M_PI / 4;
	MaxOri					= M_PI / 4;
	MaxScaleDiff			= 1.5;
	MinScale				= 0.5;
	MaxScale				= 1.5;
	Variance				= 0.1;

	BoundarySize			= 0;
	MaxFullInstCount		= 10000;
	MaxInstCount			= 200;
	MinInstCount			= 5;
	
	parseInfo				= false;
	createInfo				= false;

	fNeedRefreshMRFScore	= false;
	fNeedMakeInstTree		= false;

	FillMissing				= true;

	TripletScore_.clear();
	BaseAppearanceScore = 0.0;
	ArcScaleScore_.clear();
	ArcRotScore_.clear();
	InstScore_ = 0.0;

	// Just for beautiful data

	BottomUpTimeCost = 0.0;
	ActiveThres = 0;
}

CAndNode::~CAndNode(void)
{
}

double CAndNode::OriDiff(double ori1, double ori2)				// [-PI, PI]
{
	double	ori	= ori2 - ori1;

	while ( ori > M_PI )
	{
		ori -= M_PI * 2;
	}

	while ( ori < - M_PI )
	{
		ori	+= M_PI * 2;
	}

	return	ori;
}

int	CAndNode::DrawInstanceNode(CHiBoostImageEntity &entity, string strImageFileName)
{
	CImg<int> imgOutput;
	char strTemp[10001];

	imgOutput = entity.CurrentImageLayer.imgScaled;

	int i;
	for ( i = (int)imgOutput.size()-1; i >= 0; --i )
		imgOutput.data[i] = imgOutput.data[i]/2 + 128;
	int ix, iy;
	const Color& _color = g_Parameter.Colors[ModelID % g_Parameter.Colors.size()];
	for ( i = 0; i < (int)instances.size(); i++ )
	{
		ix = (int)instances[i].center.x;
		iy = (int)instances[i].center.y;
		imgOutput.draw_circle(
			ix, iy, g_Parameter.PointRadiusForDrawing,
			CExternalTools::GetIntArrayRGB(_color.GetValue() & 0x00ffffff));
	}
	sprintf_s(strTemp, "Amount: %d", (int)instances.size());
	CExternalTools::OutputTextToImage(imgOutput, strTemp, 8, imgOutput.height - 20, 255, 255, 255, 255, 0, 0);

	CExternalTools::mySaveImage(strImageFileName, imgOutput);

	//CImageEx			*pImage, *pOImage;
	//RGBQUAD				*pBits, *pRGB;
	//vector<Color>		colors	= g_Parameter.Colors;
	////int					LeafID;
	//int					ret;

	//// load pImage
	//pOImage	= new CImageEx();

	//CExternalTools::MakeCImageExInstance(*pOImage, entity.CurrentImageLayer.imgScaled);
	////pOImage->Load(entity.strImageFileName.c_str());

	//pOImage->ConvertToARGB32Bits();
	//pBits	= (RGBQUAD*) pOImage->GetBits();

	//// Draw Background Image
	//pImage				= new CImageEx();
	//pImage->m_pBitmap	= new Bitmap(entity.CurrentImageLayer.Scaled_W, entity.CurrentImageLayer.Scaled_H, PixelFormat32bppPARGB);
	//pRGB				= (RGBQUAD*) pImage->GetBits();
	//for ( int i = 0; i < entity.CurrentImageLayer.Scaled_H; i++ )
	//{
	//	for ( int j = 0; j < entity.CurrentImageLayer.Scaled_W; j++, pRGB++, pBits++ )
	//	{
	//		pRGB->rgbBlue		= pBits->rgbBlue / 2 + 128;
	//		pRGB->rgbGreen		= pBits->rgbGreen / 2 + 128;
	//		pRGB->rgbRed		= pBits->rgbRed / 2 + 128;
	//		pRGB->rgbReserved	= pBits->rgbReserved;
	//	}
	//}
	//pImage->FreeBits();
	//pOImage->FreeBits();
	//pOImage->Unload();
	//delete	pOImage;

	//Graphics		graphics(pImage->m_pBitmap);
	//SolidBrush		myBrush(Color(0, 0, 0));
	//Pen				myPen(&myBrush, 2);
	//Font			myFont(L"Arial Narrow", 12, FontStyleBold);
	//wstring			strShowString;
	//char			szShowText[MAX_PATH];
	//PointF			point;

	//myPen.SetWidth(3);
	//for ( int i = 0; i < (int)instances.size(); ++i)//   Instance.LeafNodeInfo.size(); i++ )
	//{
	//	//LeafID	= Instance.LeafNodeInfo[i].LeafNodeIndex;

	//	myBrush.SetColor(colors[ModelID % colors.size()]);
	//	myPen.SetColor(colors[ModelID % colors.size()]);

	//	point.X	= (float)instances[i].center.x;// Instance.LeafNodeInfo[i].node.x;
	//	point.Y	= (float)instances[i].center.y;// Instance.LeafNodeInfo[i].node.y;
	//	graphics.DrawEllipse(&myPen,   (int) (point.X - 3), (int) (point.Y - 3), (int) (2*1+1), (int) (2*1+1));
	//	graphics.FillEllipse(&myBrush, (int) (point.X - 3), (int) (point.Y - 3), (int) (2*1+1), (int) (2*1+1));
	//}

	//myPen.SetColor(Color(255, 0, 0));
	//myBrush.SetColor(Color(255, 0, 0));
	//sprintf_s(szShowText, MAX_PATH, "Amount: %d", (int)instances.size());
	//strShowString	= UTF82WChar( (const BYTE *)szShowText, (int) strlen(szShowText) );
	//point.X	= (float) (entity.CurrentImageLayer.Scaled_W - 8 * strlen(szShowText));
	//point.Y	= (float) (entity.CurrentImageLayer.Scaled_H - 20);
	//graphics.DrawString(strShowString.c_str(), (int) strShowString.length(), &myFont, point, &myBrush);

	//// Save Image
	//ret	= pImage->Save(strImageFileName.c_str());
	//delete	pImage;

	return	1;
}

int	CAndNode::BottomUpSearch(ModelTreeType &model, CHiBoostImageEntity &entity, InstanceTreeType &tree, const char* ccpPN_ParseLog)
{
	CAndNodeModel				&CurrModel	= model.AndModels[ModelID];
	int							ChildCount	= (int) CurrModel.Children.size();
	vector<BasicNodePairType>	LeafNodes;
	NodeInstanceType			Instance;
	char						fname[MAX_PATH];
	CTimer						timer;
	int							ret;

	if (parseInfo)
	{
		return	1;
	}

	if (CurrModel.NodeType == 0)
	{
		timer.Reset();
		timer.Start();

		ret	= MakeLeafNodeInstance_BottomUp(model, entity);
		ret	= RemoveReduntantInstance_BottomUp(model);

		timer.Stop();

		parseInfo			= true;
		BottomUpTimeCost	= timer.GetElapsedTime();
	}
	
	if (CurrModel.NodeType == 1)
	{
		for ( int i = 0; i < ChildCount; i++ )
		{
			ret	= tree.OrNodes[children[i]].BottomUpSearch(model, entity, tree, ccpPN_ParseLog);
		}

		timer.Reset();
		timer.Start();

		fullInst.clear();
		fullInst.reserve(MaxFullInstCount);
		Instance.source.resize(ChildCount);
		Instance.ChildCenters.resize(ChildCount);
		ActiveThres = 1;
		ret			= MakeAndNodeInstance_BottomUp(model, tree, entity, 0, Instance);
		ret			= RemoveReduntantInstance_BottomUp(model);
		//if ((int) instances.size() < MinInstCount)
		//{
		//	fullInst.clear();
		//	ActiveThres = 0;
		//	ret			= MakeAndNodeInstance_BottomUp(model, tree, entity, 0, Instance);
		//	ret			= RemoveReduntantInstance_BottomUp(model);
		//}

		timer.Stop();
		parseInfo			= true;
		BottomUpTimeCost	= timer.GetElapsedTime();
	}

	CExternalTools::ConsoleTools::ClearCurrentLine();
	cout<<setw(2)<<ModelID<<setw(8)<<instances.size()<<setw(8)<<fullInst.size();

	if ((ModelID == model.Root) && (instances.size() > 0))
	{
		if (ccpPN_ParseLog!=NULL && *ccpPN_ParseLog)
		{
			for ( int i = 0; i < __min(10, (int) instances.size()); i++ )
			{
				sprintf_s(fname, MAX_PATH, "%sResult.%04d.jpg", ccpPN_ParseLog, i);
				ret	= DrawInstance(model, entity, instances[i], fname);
			}
		}
	}

	if (ccpPN_ParseLog!=NULL && *ccpPN_ParseLog)
	{
		sprintf_s(fname, MAX_PATH, "%sPerNode.%04d.jpg", ccpPN_ParseLog, ModelID);
		ret	= DrawInstanceNode(entity, fname);
	}

	return	1;
}

int	CAndNode::MakeLeafNodeInstance_BottomUp(ModelTreeType &model, CHiBoostImageEntity &entity)
{
	CAndNodeModel		&CurrModel	= model.AndModels[ModelID];
	CLeafNodeModel		&LeafModel	= model.LeafModels[leafIndex];
	BasicNodePairType	node_pair;
	NodeInstanceType	instance;
	//double				Rotate;
	int					ret;

	fullInst.clear();
	fullInst.reserve(MaxFullInstCount);
	const CHiBoostImageLayer::CPixRef* qpr = entity.PtrPixRef;

	for ( int i = 0; i < entity.Amount_PixRef; i++ )
	{
		//Rotate	= OriDiff(2*LeafModel.ori, 2*entity.PtrPixRef[i].gradient_orientation) / 2;
		//////Rotate	= OriDiff(2*.ori, 2*entity.nodes[i].ori) / 2;
		////////Rotate	= - OriDiff(2*LeafModel.ori, 2*entity.nodes[i].ori) / 2;
		//if (fabs(Rotate) > MaxOri)
		//{
		//	//yuanlin
		//	//continue;
		//}

		instance.LeafNodeInfo.clear();
		instance.source.clear();

		node_pair.LeafNodeIndex	= leafIndex;	
		node_pair.node.x		= entity.PtrPixRef[i].layer_fx; //// entity.nodes[i].x;
		node_pair.node.y		= entity.PtrPixRef[i].layer_fy; //// entity.nodes[i].y;
		node_pair.node.ori		= 0.0; // entity.PtrPixRef[i].gradient_orientation; //// entity.nodes[i].ori;
		node_pair.Missing		= 0;
		node_pair.FixCount		= 1;

		instance.LeafNodeInfo.push_back(node_pair);
		instance.source.push_back(i);
		instance.center.x		= entity.PtrPixRef[i].layer_fx; //// entity.nodes[i].x;
		instance.center.y		= entity.PtrPixRef[i].layer_fy; //// entity.nodes[i].y;
		instance.center.ori		= 0.0; // Rotate;
		instance.center.scale	= 1.0;
		instance.center.OrIndex = -1;

		instance.Score	= 0.0;
		instance.ShapeScore = 0.0;

		//if (instance.center.x>239 && instance.center.x<249 && instance.center.y>355 && instance.center.y<365)
		//	i = i;

		instance.NodeBaseAppearanceScore = entity.GetAppearanceScore_LayerCoordinate(
			instance.center.x, instance.center.y, 1.0, ModelID);
		instance.AppearanceScore = instance.NodeBaseAppearanceScore * CurrModel.AppearanceWeight;

		////instance.NodeBaseAppearanceScore = 0;
		////instance.AppearanceScore = 0;
		////ret	= LeafModel.ConvertFeature(entity.nodes[i].feature, LeafFeature_);
		////for ( int j = 0; j < (int) LeafModel.Weights.size(); j++ )
		////{
		////	instance.AppearanceScore	+= LeafModel.Weights[j] * LeafFeature_[j];
		////}
		
		instance.Score += instance.AppearanceScore;

		if (instance.Score < CurrModel.Threshold[model.RuleStep-1])
		{
			continue;
		}

		ret	= AddInstanceArcCenters(model, instance);
		fullInst.push_back(instance);
	}

	return	1;
}

int CAndNode::AddInstanceArcCenters(ModelTreeType &model, NodeInstanceType &Instance)
{
	BasicInstInfoType	center;

	Instance.Centers.clear();
	for ( int t = 0; t < (int) CenterIndex.size(); t++ )
	{
		for ( int i = 0; i < (int) Instance.LeafNodeInfo.size(); i++ )
		{
			if (Instance.LeafNodeInfo[i].LeafNodeIndex == CenterIndex[t])
			{
				center.x		= Instance.LeafNodeInfo[i].node.x;
				center.y		= Instance.LeafNodeInfo[i].node.y;
				center.ori		= Instance.LeafNodeInfo[i].node.ori;
				center.scale	= 1.0;
				center.OrIndex = -1;

				Instance.Centers.push_back(center);
			}
		}
	}

	return	1;
}

int	CAndNode::FreeFullInstanceSet()
{
	vector<NodeInstanceType>	NullInsts;
	vector<int>					NullIndexs;

	NullInsts.swap(fullInst);
	NullIndexs.swap(fullIndex);
	return	1;
}

int	CAndNode::RemoveReduntantInstance_BottomUp(ModelTreeType &model)
{
	CAndNodeModel	&CurrModel	= model.AndModels[ModelID];
	int				Thres		= (int) fullInst.size();

	instances.clear();
	sort(fullInst.begin(), fullInst.end(), SortByInstanceScore);
	fullIndex.assign(fullInst.size(), -1);

	for ( int i = 0; i < (int) fullInst.size(); i++ )
	{
		for ( int j = 0; j < (int) instances.size(); j++ )
		{
			if (InstanceSimilar(model, ModelID, fullInst[i], instances[j]))
			{
				fullIndex[i]	= j;
				break;
			}
		}
		if (fullIndex[i] < 0)
		{
			fullIndex[i]	= (int) instances.size();
			instances.push_back(fullInst[i]);
			if (instances.size() == g_Parameter.m_MaxInstCount[Level])
			{
				Thres	= i;
				break;
			}
		}
	}

	int InstCount	= __min((int) instances.size(), g_Parameter.m_MaxInstCount[Level]);
	instances.resize(InstCount);
	fullInst.resize(Thres);
	fullIndex.resize(Thres);
	ConstrainIndex.assign(InstCount, 0);
	return	1;
}

bool CAndNode::InstanceSimilar(ModelTreeType &model, int NodeIndex, NodeInstanceType &p1, NodeInstanceType &p2)
{
	CAndNodeModel	&CurrModel	= model.AndModels[NodeIndex];
	double			ScaleDiff, RotDiff, PosDiff;

	// Center
	ScaleDiff	= p1.center.scale / p2.center.scale;
	RotDiff		= fabs(OriDiff(p1.center.ori, p2.center.ori));
	PosDiff		= sqrt((p1.center.x - p2.center.x) * (p1.center.x - p2.center.x) + (p1.center.y - p2.center.y) * (p1.center.y - p2.center.y));
	//PosDiff /= sqrt(p1.center.scale * p2.center.scale);

	if ((ScaleDiff > g_Parameter.m_fMaxScale_NMS) || (ScaleDiff < g_Parameter.m_fMinScale_NMS))
		return false;
	if ((RotDiff > g_Parameter.m_fMaxOriDiff_NMS) && (CurrModel.NodeType == 1))
		return	false;
	if ((RotDiff > g_Parameter.m_fLeafOriDiff_NMS) && (CurrModel.NodeType == 0))
		return	false;
	if (PosDiff > g_Parameter.m_NearArea_NMS[CurrModel.Level])
		return	false;

	for ( int t = 0; t < (int) p1.Centers.size(); t++ )
	{
		PosDiff	=  (p1.Centers[t].x - p2.Centers[t].x) * (p1.Centers[t].x - p2.Centers[t].x);
		PosDiff	+= (p1.Centers[t].y - p2.Centers[t].y) * (p1.Centers[t].y - p2.Centers[t].y);
		PosDiff	= sqrt(PosDiff);

		if (PosDiff > g_Parameter.m_NearArea_NMS[CurrModel.Level])
			return	false;
	}

	return	true;
}

int CAndNode::MakeInstanceRotateAndScaleByLeafNodes(ModelTreeType &model, InstanceTreeType &tree, NodeInstanceType &Instance)
{
	vector<BasicNodePairType>		LeafNodes;
	double							x1, y1, x2, y2;
	double							r1, l1, r2, l2;
	int								Count;
	int								ret;

	ret	= MakeInstanceLeafNodes(model, tree, Instance, LeafNodes);

	Count					= 0;
	Instance.center.x		= 0;
	Instance.center.y		= 0;
	Instance.center.ori		= 0;
	Instance.center.scale	= 0.0;
	Instance.center.OrIndex = -1;

	for ( int i = 0; i < (int) LeafNodes.size(); i++ )
	{
		if (LeafNodes[i].FixCount != 0)
		{
			continue;
		}

		x1	= LeafNodes[i].node.x;
		y1	= LeafNodes[i].node.y;

		for ( int j = i + 1; j < (int) LeafNodes.size(); j++ )
		{
			if (LeafNodes[j].FixCount != 0)
			{
				continue;
			}

			x2	= LeafNodes[j].node.x;
			y2	= LeafNodes[j].node.y;

			l1	= __max(1, sqrt((x1-x2)*(x1-x2) + (y1-y2) *(y1-y2)));
			r1	= (y2 > y1) ? (acos((x2 - x1) / l1)) : (-acos((x2 - x1) / l1));
			l2	= model.LeafLenInfo[i][j];
			r2	= model.LeafDirInfo[i][j];

			Instance.center.ori		+= OriDiff(r2, r1);
			Instance.center.scale	+= l1 / l2;
			//Instance.center.scale	+= log(l1 / l2);
			Count++;
		}
	}

	Count					= __max(1, Count);
	Instance.center.ori		/= Count;
	Instance.center.scale	/= Count;
	//Instance.center.scale	= exp(Instance.center.scale / Count);

	//yuanlin

	return	1;
}

int	CAndNode::MakeInstanceRotateAndScale(ModelTreeType &model, NodeInstanceType &Instance)
{
	CAndNodeModel	&CurrModel	= model.AndModels[ModelID];
	int				ChildCount	= (int) children.size();
	double			x1, y1, x2, y2;
	double			r1, l1, r2, l2;
	int				m1, m2;
	int				Count;

	Count					= 0;
	Instance.center.x		= 0;
	Instance.center.y		= 0;
	Instance.center.ori		= 0;
	Instance.center.scale	= 0.0;
	Instance.center.OrIndex = -1;
	for ( int i = 0; i < ChildCount; i++ )
	{
		if (Instance.source[i] < 0)
		{
			continue;
		}

		m1	= CurrModel.NodeModelIndex[i] + Instance.ChildCenters[i].OrIndex;
		x1	= Instance.ChildCenters[i].x;
		y1	= Instance.ChildCenters[i].y;

		for ( int j = i + 1; j < ChildCount; j++ )
		{
			if (Instance.source[j] < 0)
			{
				continue;
			}

			m2	= CurrModel.NodeModelIndex[j] + Instance.ChildCenters[j].OrIndex;
			x2	= Instance.ChildCenters[j].x;
			y2	= Instance.ChildCenters[j].y;

			l1	= __max(1, sqrt((x1-x2)*(x1-x2) + (y1-y2) *(y1-y2)));
			r1	= (y2 > y1) ? (acos((x2 - x1) / l1)) : (-acos((x2 - x1) / l1));
			l2	= CurrModel.NodeLenInfo[m1][m2];
			r2	= CurrModel.NodeDirInfo[m1][m2];

			Instance.center.ori		+= OriDiff(r2, r1);
			Instance.center.scale	+= l1 / l2;
			//Instance.center.scale	+= log(l1 / l2);
			Count++;
		}
	}

	Count					= __max(1, Count);
	Instance.center.ori		/= Count;
	Instance.center.scale	/= Count;
	//Instance.center.scale	= exp(Instance.center.scale / Count);

	//yuanlin

	return	1;
}

int	CAndNode::FillInMissChildNode_BottomUp(ModelTreeType &model, InstanceTreeType &tree, CHiBoostImageEntity &entity, NodeInstanceType &Instance)
{
	CAndNodeModel	&CurrModel	= model.AndModels[ModelID];
	int				ChildCount	= (int) children.size();
	int				MissMID, CurrMID, MissSource;
	double			Scale, Rotate;
	int				Count;

	Scale	= Instance.center.scale;
	Rotate	= Instance.center.ori;

	for ( int i = 0; i < ChildCount; i++ )
	{
		if (Instance.source[i] >= 0)
		{
			continue;
		}

		Count						= 0;
		Instance.ChildCenters[i].x	= 0;
		Instance.ChildCenters[i].y	= 0;
		MissSource					= model.OrModels[children[i]].MissSource;
		MissMID						= CurrModel.NodeModelIndex[i] + MissSource;

		for ( int j = 0; j < ChildCount; j++ )
		{
			if (Instance.source[j] >= 0)
			{
				CurrMID						= CurrModel.NodeModelIndex[j] + Instance.ChildCenters[j].OrIndex;
				Instance.ChildCenters[i].x	+= Instance.ChildCenters[j].x + Scale * CurrModel.NodeLenInfo[CurrMID][MissMID] * cos(Rotate + CurrModel.NodeDirInfo[CurrMID][MissMID]);
				Instance.ChildCenters[i].y	+= Instance.ChildCenters[j].y + Scale * CurrModel.NodeLenInfo[CurrMID][MissMID] * sin(Rotate + CurrModel.NodeDirInfo[CurrMID][MissMID]);
				//Instance.ChildCenters[i].x	+= Instance.ChildCenters[j].x + Scale * CurrModel.NodeLenInfo[j][i] * cos(Rotate + CurrModel.NodeDirInfo[j][i]);
				//Instance.ChildCenters[i].y	+= Instance.ChildCenters[j].y + Scale * CurrModel.NodeLenInfo[j][i] * sin(Rotate + CurrModel.NodeDirInfo[j][i]);
				Count++;
			}
		}

		Instance.ChildCenters[i].x			/= Count;
		Instance.ChildCenters[i].y			/= Count;
		Instance.ChildCenters[i].ori		= Instance.center.ori;
		Instance.ChildCenters[i].scale		= Instance.center.scale;
		Instance.ChildCenters[i].OrIndex  = MissSource;
	}

	return	1;
}

int CAndNode::FillInMissTree_BottomUp(ModelTreeType &model, InstanceTreeType &tree, CHiBoostImageEntity &entity, NodeInstanceType &Instance)
{
	CAndNodeModel					&CurrModel	= model.AndModels[ModelID];
	int								ChildCount	= (int) children.size();
	InstanceTreeType				MissTree;
	vector<BasicNodePairType>		MissNodes, LeafNodes;
	vector<int>						NodeIndex, MissIndex;
	int								MissID, MissNodeID;
	int								InstID;
	int								ret;

	MissID	= -1;
	for ( int i = 0; i < ChildCount; i++ )
	{
		if (Instance.source[i] < 0)
		{
			if (MissID >= 0)
			{
				return	-1;
			}

			MissNodeID	= children[i];
			MissID		= i;
		}
	}

	if (MissID < 0)
	{
		return	-2;			// -2
	}

	// Group
	for ( int i = 0; i < tree.OrNodes[MissNodeID].InstCount; i++ )
	{
		double	x1		= tree.OrNodes[MissNodeID].instances[i].center.x;
		double	y1		= tree.OrNodes[MissNodeID].instances[i].center.y;
		double	r1		= tree.OrNodes[MissNodeID].instances[i].center.ori;
		double	s1		= tree.OrNodes[MissNodeID].instances[i].center.scale;
		double	x2		= Instance.ChildCenters[MissID].x;
		double	y2		= Instance.ChildCenters[MissID].y;
		double	r2		= Instance.ChildCenters[MissID].ori;
		double	s2		= Instance.ChildCenters[MissID].scale;
		double	RDiff	= fabs(OriDiff(r1, r2));
		double	SDiff	= s2 / s1;
		double	PDiff	= sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
		int		Level = CurrModel.Level + 1;

		if (RDiff > g_Parameter.m_fMaxOriDiff_FillIn)
			continue;

		if ((s1 > 0) && ((SDiff < g_Parameter.m_fMinScale_FillIn) || (SDiff > g_Parameter.m_fMaxScale_FillIn)))
			continue;

		if (PDiff >  g_Parameter.m_NearArea_FillIn[Level])
			continue;

		return	-1;
	}

	for ( int i = tree.OrNodes[MissNodeID].InstCount; i < (int) tree.OrNodes[MissNodeID].instances.size(); i++ )
	{
		double	x1		= tree.OrNodes[MissNodeID].instances[i].center.x;
		double	y1		= tree.OrNodes[MissNodeID].instances[i].center.y;
		double	r1		= tree.OrNodes[MissNodeID].instances[i].center.ori;
		double	s1		= tree.OrNodes[MissNodeID].instances[i].center.scale;
		double	x2		= Instance.ChildCenters[MissID].x;
		double	y2		= Instance.ChildCenters[MissID].y;
		double	r2		= Instance.ChildCenters[MissID].ori;
		double	s2		= Instance.ChildCenters[MissID].scale;
		double	RDiff	= fabs(OriDiff(r1, r2));
		double	SDiff	= s2 / s1;
		double	PDiff	= sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
		int		Level = CurrModel.Level + 1;

		if (RDiff > g_Parameter.m_fMaxOriDiff_FillIn)
			continue;

		if ((s1 > 0) && ((SDiff < g_Parameter.m_fMinScale_FillIn) || (SDiff > g_Parameter.m_fMaxScale_FillIn)))
			continue;

		if (PDiff >  g_Parameter.m_NearArea_FillIn[Level])
			continue;

		Instance.source[MissID]			= i;
		Instance.ChildCenters[MissID]	= tree.OrNodes[MissNodeID].instances[i].center;
		ret	= MakeInstanceRotateAndScaleByLeafNodes(model, tree, Instance);
		if (!UnderGeoConstrain_BottomUp(model, Instance))
		{
			Instance.source[MissID]	= -1;
			return	-1;
		}
		else
		{
			return	MissID;
		}
	}

	// Make Instance From LeafNodes
	MissNodes.resize((int) model.OrModels[MissNodeID].MissLeafNode.size());
	ret	= MakeInstanceLeafNodes(model, tree, Instance, LeafNodes);
	for ( int i = 0; i < (int) MissNodes.size(); i++ )
	{
		MissNodes[i].Missing		= 0;
		MissNodes[i].FixCount		= 0;
		MissNodes[i].node.x			= 0;
		MissNodes[i].node.y			= 0;
		MissNodes[i].node.ori		= 0;
		MissNodes[i].LeafNodeIndex	= model.OrModels[MissNodeID].MissLeafNode[i];
		for ( int j = 0; j < (int) LeafNodes.size(); j++ )
		{
			if (LeafNodes[j].FixCount == 0)
			{
				int		LeafID1	= MissNodes[i].LeafNodeIndex;
				int		LeafID2 = LeafNodes[j].LeafNodeIndex;
				double	Len		= model.LeafLenInfo[LeafID2][LeafID1];
				double	Ori		= model.LeafDirInfo[LeafID2][LeafID1];
				double	Scale	= Instance.center.scale;
				double	Rot		= Instance.center.ori;

				MissNodes[i].node.x	+= LeafNodes[j].node.x + Scale * Len * cos(Ori + Rot);
				MissNodes[i].node.y	+= LeafNodes[j].node.y + Scale * Len * sin(Ori + Rot);
				MissNodes[i].FixCount++;
			}
		}

		MissNodes[i].FixCount	= __max(1, MissNodes[i].FixCount);
		MissNodes[i].node.x		/= MissNodes[i].FixCount;
		MissNodes[i].node.y		/= MissNodes[i].FixCount;
		MissNodes[i].FixCount	= 0;

		if ((MissNodes[i].node.x < BoundarySize) || (MissNodes[i].node.y < BoundarySize))
		{
			return	-1;
		}
		if ((MissNodes[i].node.x > tree.Width - BoundarySize - 1) || (MissNodes[i].node.y > tree.Height - BoundarySize - 1))
		{
			return	-1;
		}
	}

	ret	= MakeInstFromLeafNodes(model, tree, MissTree, entity, MissNodes, MissNodeID);

	InstID							= (int) tree.OrNodes[MissNodeID].instances.size();
	Instance.source[MissID]			= InstID;
	Instance.ChildCenters[MissID]	= MissTree.OrNodes[MissNodeID].instances[0].center;
	tree.OrNodes[MissNodeID].instances.push_back(MissTree.OrNodes[MissNodeID].instances[0]);

	ret	= MakeInstanceRotateAndScaleByLeafNodes(model, tree, Instance);
	if (!UnderGeoConstrain_BottomUp(model, Instance))
	{
		Instance.source[MissID]	= -1;
		tree.OrNodes[MissNodeID].instances.pop_back();
		return	-1;
	}

	ret	= tree.OrNodes[MissNodeID].FillInInstInTree(tree, MissTree, Instance.source[MissID]);

	return	MissID;
}

int	CAndNode::MakeInstFromLeafNodes(ModelTreeType &model, InstanceTreeType &CurrTree, InstanceTreeType &MissTree, CHiBoostImageEntity &entity, vector<BasicNodePairType> &LeafNodes, int OrNodeID)
{
	InstanceTreeType	TemplateTree;
	vector<int>			NodeIndex;
	int					LeafID;
	////int					NodeID;
	int					ret;

	TemplateTree.Root	= model.Root;
	TemplateTree.AndNodes.resize(model.AndModels.size());
	TemplateTree.OrNodes.resize(model.OrModels.size());
	for ( int i = 0; i < (int) model.AndModels.size(); i++ )
	{
		TemplateTree.AndNodes[i].parseInfo		= false;
		TemplateTree.AndNodes[i].fNeedMakeInstTree = true;

		TemplateTree.AndNodes[i].ModelID		= i;
		TemplateTree.AndNodes[i].Level 		= model.AndModels[i].Level;
		TemplateTree.AndNodes[i].NodeType		= model.AndModels[i].NodeType;
		TemplateTree.AndNodes[i].leafIndex		= model.AndModels[i].LeafIndex;
		TemplateTree.AndNodes[i].children		= model.AndModels[i].Children;
		TemplateTree.AndNodes[i].CenterIndex	= CurrTree.AndNodes[i].CenterIndex;

		TemplateTree.AndNodes[i].instances.clear();
	}
	for ( int i = 0; i < (int) model.OrModels.size(); i++ )
	{
		TemplateTree.OrNodes[i].parseInfo	= false;
		TemplateTree.OrNodes[i].fNeedMakeInstTree = true;

		TemplateTree.OrNodes[i].ModelID		= i;
		TemplateTree.OrNodes[i].Level 	= model.OrModels[i].Level;
		TemplateTree.OrNodes[i].children	= model.OrModels[i].Children;
		TemplateTree.OrNodes[i].CenterIndex	= CurrTree.OrNodes[i].CenterIndex;
	}

	MissTree		= TemplateTree;
	MissTree.Width	= entity.CurrentImageLayer.Scaled_W;
	MissTree.Height	= entity.CurrentImageLayer.Scaled_H;

	for ( int i = 0; i < (int) LeafNodes.size(); i++ )
	{
		LeafID	= LeafNodes[i].LeafNodeIndex;

		for ( int j = 0; j < (int) MissTree.AndNodes.size(); j++ )
		{
			if (MissTree.AndNodes[j].leafIndex != LeafID)
			{
				continue;
			}

			CLeafNodeModel		&CurrModel	= model.LeafModels[LeafID];
			BasicNodePairType	node_pair;
			NodeInstanceType	inst;

			const CHiBoostImageLayer::CPixRef* ppr = entity.FindNearestSampledPixel_LayerCoordinate(LeafNodes[i].node.x, LeafNodes[i].node.y);
			////ret	= entity.FindNearestNodes(LeafNodes[i].node.x, LeafNodes[i].node.y, NodeID);

			node_pair.LeafNodeIndex	= LeafID;	
			node_pair.node.x		= ppr->layer_fx; //// entity.nodes[NodeID].x;
			node_pair.node.y		= ppr->layer_fy; //// entity.nodes[NodeID].y;
			node_pair.node.ori		= 0.0; // ppr->gradient_orientation; //// entity.nodes[NodeID].ori;
			node_pair.Missing		= 0;
			node_pair.FixCount		= 1;

			inst.LeafNodeInfo.push_back(node_pair);
			inst.source.push_back(ppr->index);
			////inst.source.push_back(NodeID);
			inst.center.x			= node_pair.node.x;
			inst.center.y			= node_pair.node.y;
			inst.center.ori			= OriDiff(2 * CurrModel.ori, 2 * node_pair.node.ori) / 2;
			inst.center.scale		= 1.0;
			//inst.center.ori			= - OriDiff(2 * CurrModel.ori, 2 * node_pair.node.ori) / 2;
			//inst.center.scale		= -1.0;
			inst.center.OrIndex 	= -1;

			inst.Score					= 0;
			inst.ShapeScore			= 0.0;
			inst.NodeBaseAppearanceScore = entity.GetAppearanceScore_LayerCoordinate(
				ppr->layer_fx, ppr->layer_fy, 1.0, j);
			inst.AppearanceScore	= inst.NodeBaseAppearanceScore * model.AndModels[j].AppearanceWeight;

			////inst.NodeBaseAppearanceScore = 0;
			////inst.AppearanceScore = 0;
			////ret			= CurrModel.ConvertFeature(entity.nodes[NodeID].feature, MissTree.AndNodes[j].LeafFeature_);
			////for ( int k = 0; k < (int) CurrModel.Weights.size(); k++ )
			////{
			////	inst.AppearanceScore	+= CurrModel.Weights[k] * MissTree.AndNodes[j].LeafFeature_[k];
			////}
			
			inst.Score += inst.AppearanceScore;

			MissTree.AndNodes[j].instances.clear();
			MissTree.AndNodes[j].instances.push_back(inst);
			break;
		}
	}

	ret	= MissTree.OrNodes[OrNodeID].MakeInstTree(model, entity, MissTree, true);

	for ( int i = 0; i < (int) model.OrModels.size(); i++ )
		MissTree.OrNodes[i].fNeedMakeInstTree = true;
	for ( int i = 0; i < (int) model.OrModels.size(); i++ )
		MissTree.OrNodes[i].fNeedMakeInstTree = true;

	return	1;
}

int	CAndNode::FillInInstInTree(InstanceTreeType &tree, InstanceTreeType &tree_fillin, int InstID)
{
	int		ChildCount	= (int) children.size();
	int		ret;

	if (NodeType == 0)
	{
		return	1;
	}

	for ( int i = 0; i < ChildCount; i++ )
	{
		instances[InstID].source[i]	= (int) tree.OrNodes[children[i]].instances.size();
		tree.OrNodes[children[i]].instances.push_back(tree_fillin.OrNodes[children[i]].instances[0]);
		ret	= tree.OrNodes[children[i]].FillInInstInTree(tree, tree_fillin, instances[InstID].source[i]);
	}

	return	1;
}

int CAndNode::MakeAndNodeInstance_BottomUp(ModelTreeType &model, InstanceTreeType &tree, CHiBoostImageEntity &entity, int ChildID, NodeInstanceType &Instance)
{
	CAndNodeModel	&CurrModel	= model.AndModels[ModelID];
	int				MissID;
	int				ret;

	if ( ChildID >= (int) children.size() )
	{
		ret	= MakeInstanceRotateAndScaleByLeafNodes(model, tree, Instance);
		if (UnderGeoConstrain_BottomUp(model, Instance))
		{
			ret		= FillInMissChildNode_BottomUp(model, tree, entity, Instance);
			MissID	= FillInMissTree_BottomUp(model, tree, entity, Instance);
			if (MissID != -1)
			{
				//YUAN
				ret	= MakeInstanceLeafInfo(model, tree, Instance);
				MakeBaseAppearanceScore(entity, Instance);
				ret	= MakeMRFScore(model, tree, Instance);

				//ret	= MakeMRFScore(model, tree, Instance);
				//ret	= MakeInstanceLeafInfo(model, tree, Instance);

				ret	= AddInstanceArcCenters(model, Instance);
				ret	= AddInstance_BottomUp(model, Instance);

				if (MissID >= 0)
				{
					Instance.source[MissID]	= -1;
				}
			}
		}
	}
	else
	{
		vector<NodeInstanceType>	&ChildInsts	= tree.OrNodes[children[ChildID]].instances;

		for ( int i = 0; i < tree.OrNodes[children[ChildID]].InstCount; i++ )
		{
			Instance.source[ChildID]		= i;
			Instance.ChildCenters[ChildID]	= ChildInsts[i].center;

			if (UnderGeoConstrain_BottomUp(model, Instance, ChildID))
			{
				ret	= MakeAndNodeInstance_BottomUp(model, tree, entity, ChildID + 1, Instance);
			}
		}

		Instance.source[ChildID]	= -1;
		ret	= MakeAndNodeInstance_BottomUp(model, tree, entity, ChildID + 1, Instance);
	}

	return	1;
}

bool CAndNode::UnderGeoConstrain_BottomUp(ModelTreeType &model, NodeInstanceType &Instance, int CurrID)
{
	CAndNodeModel	&CurrModel	= model.AndModels[ModelID];
	double			s1			= Instance.ChildCenters[CurrID].scale;
	double			r1			= Instance.ChildCenters[CurrID].ori;
	double			x1			= Instance.ChildCenters[CurrID].x;
	double			y1			= Instance.ChildCenters[CurrID].y;
	int				m1			= Instance.ChildCenters[CurrID].OrIndex + CurrModel.NodeModelIndex[CurrID];

	for ( int i = 0; i < CurrID; i++ )
	{
		if (Instance.source[i] >= 0)
		{
			double	s2		= Instance.ChildCenters[i].scale;
			double	r2		= Instance.ChildCenters[i].ori;
			double	x2		= Instance.ChildCenters[i].x;
			double	y2		= Instance.ChildCenters[i].y;
			int		m2		= Instance.ChildCenters[i].OrIndex + CurrModel.NodeModelIndex[i];

			double	DiffScale	= __max(s2 / s1, s1 / s2);
			double	DiffOri		= OriDiff(r1, r2);
			if ((DiffScale > MaxScaleDiff) || (fabs(DiffOri) > MaxOriDiff))
			{
				return	false;
			}

			double	d		= __max(1, sqrt((x1-x2)*(x1-x2) + (y1-y2) *(y1-y2)));
			double	r		= (y2 > y1) ? (acos((x2 - x1) / d)) : (-acos((x2 - x1) / d));
			double	md		= CurrModel.NodeLenInfo[m1][m2];
			double	mr		= CurrModel.NodeDirInfo[m1][m2];
			double	scale	= d / md;
			double	rotate	= OriDiff(mr, r);
			if ((scale < MinScale) || (scale > MaxScale) || (fabs(rotate) > MaxOri))
			{
				return	false;
			}

			for ( int j = 0; j <= CurrID; j++ )
			{
				if ((j == i) || (j == CurrID))															// Modify
				{
					double	DiffScale	= __max(scale / Instance.ChildCenters[j].scale, Instance.ChildCenters[j].scale / scale);
					double	DiffOri		= OriDiff(rotate, Instance.ChildCenters[j].ori);
					if (((DiffScale > MaxScaleDiff) && (Instance.ChildCenters[j].scale > 0)) || (fabs(DiffOri) > MaxOriDiff))
					{
						return	false;
					}
				}
			}
		}
	}

	return	true;
}

bool CAndNode::UnderGeoConstrain_BottomUp(ModelTreeType &model, NodeInstanceType &Instance)
{
	CAndNodeModel	&CurrModel	= model.AndModels[ModelID];
	
	if ((fabs(Instance.center.ori) > MaxOri) || (Instance.center.scale > MaxScale) || (Instance.center.scale < MinScale))
	{
		return	false;
	}

	return	true;
}

int	CAndNode::MakeTripletFeature(
	const CAndNodeModel::TripletType& triplet, const ModelTreeType& model,
	BasicInstInfoType &node1, BasicInstInfoType &node2, BasicInstInfoType &node3,
	vector<double> &feature, BasicInstInfoType &node)
{
	double		ori12, ori23, ori31;
	double		d12, d23, d31, sum;

	d12		= __max(1, sqrt((node1.x - node2.x) * (node1.x - node2.x) + (node1.y - node2.y) * (node1.y - node2.y)));
	d23		= __max(1, sqrt((node2.x - node3.x) * (node2.x - node3.x) + (node2.y - node3.y) * (node2.y - node3.y)));
	d31		= __max(1, sqrt((node3.x - node1.x) * (node3.x - node1.x) + (node3.y - node1.y) * (node3.y - node1.y)));
	sum		= d12 + d23 + d31;

	ori12	= (node2.y > node1.y) ? acos((node2.x - node1.x) / d12) : - acos((node2.x - node1.x) / d12);
	ori23	= (node3.y > node2.y) ? acos((node3.x - node2.x) / d23) : - acos((node3.x - node2.x) / d23);
	ori31	= (node1.y > node3.y) ? acos((node1.x - node3.x) / d31) : - acos((node1.x - node3.x) / d31);

	const CAndNodeModel& CurrModel = model.AndModels[ModelID];
	feature.resize(12);

	feature[0]	= node1.ori - ori12;
	feature[1]	= node2.ori - ori23;
	feature[2]	= node3.ori - ori31;
	if (model.AndModels[CurrModel.Children[triplet.p1]].NodeType == 0)	feature[0] = 0.0;
	if (model.AndModels[CurrModel.Children[triplet.p2]].NodeType == 0)	feature[1] = 0.0;
	if (model.AndModels[CurrModel.Children[triplet.p3]].NodeType == 0)	feature[2] = 0.0;

	feature[3]	= M_PI + ori31 - ori12;
	feature[4]	= M_PI + ori12 - ori23;
	feature[5]	= M_PI + ori23 - ori31;

	feature[6]	= d12 * 3 / sum;
	feature[7]	= d23 * 3 / sum;
	feature[8]	= d31 * 3 / sum;

	feature[9]	= __max(node1.scale / node2.scale, node2.scale / node1.scale);
	feature[10]	= __max(node2.scale / node3.scale, node3.scale / node2.scale);
	feature[11]	= __max(node3.scale / node1.scale, node1.scale / node3.scale);
	if (model.AndModels[CurrModel.Children[triplet.p1]].NodeType == 0)	feature[9] = 1.0;
	if (model.AndModels[CurrModel.Children[triplet.p2]].NodeType == 0)	feature[10] = 1.0;
	if (model.AndModels[CurrModel.Children[triplet.p3]].NodeType == 0)	feature[11] = 1.0;

	return	1;
}

double CAndNode::MakeTripletScore(ModelTreeType &model, int TripletID, vector<double> &feature)			// depend on the feature definition
{
	CAndNodeModel	&CurrModel	= model.AndModels[ModelID];
	vector<double>	&mean		= CurrModel.triplets[TripletID].feature;
	vector<double>	&var		= CurrModel.triplets[TripletID].variance;
	double			Score, diff;
	int				dim;

	dim		= (int) feature.size();
	Score	= 0;

	// the difference between orientation
	for ( int i = 0; i < 6; i++ )
	{
		if (var[i] > g_Parameter.epsilon)
		{
			diff	= OriDiff(mean[i], feature[i]);
			Score	-= (diff * diff) / (2 * var[i] * var[i]);
			Score	-= log( var[i] * sqrt(2 * M_PI) );
		}
	}

	for ( int i = 6; i < dim; i++ )
	{
		if (var[i] > g_Parameter.epsilon )
		{
			diff	= feature[i] - mean[i];
			Score	-= (diff * diff) / (2 * var[i] * var[i]);
			Score	-= log( var[i] * sqrt(2 * M_PI) );
		}
	}

	Score	/= dim;
	return	Score;
}

void CAndNode::MakeBaseAppearanceScore(CHiBoostImageEntity &entity, NodeInstanceType &Instance)
{
	Instance.NodeBaseAppearanceScore = entity.GetAppearanceScore_LayerCoordinate(Instance.center.x, Instance.center.y, Instance.center.scale, ModelID);
	//double lx, ly, hx, hy, cx, cy;
	//
	//if ((int)Instance.LeafNodeInfo.size() < 1)
	//{
	//	cout<<endl<<"ERROR!!!"<<endl;
	//	exit(0);
	//}

	//for ( int i = 0; i < (int)Instance.LeafNodeInfo.size(); ++i )
	//{
	//	if (i==0 || lx>Instance.LeafNodeInfo[i].node.x) lx = Instance.LeafNodeInfo[i].node.x;
	//	if (i==0 || ly>Instance.LeafNodeInfo[i].node.y) ly = Instance.LeafNodeInfo[i].node.y;
	//	if (i==0 || hx<Instance.LeafNodeInfo[i].node.x) hx = Instance.LeafNodeInfo[i].node.x;
	//	if (i==0 || hy<Instance.LeafNodeInfo[i].node.y) hy = Instance.LeafNodeInfo[i].node.y;
	//}
	//cx = (lx + hx) * 0.5;
	//cy = (ly + hy) * 0.5;

	//Instance.NodeBaseAppearanceScore = entity.GetAppearanceScore_LayerCoordinate(cx, cy, Instance.center.scale, ModelID);
}

int CAndNode::MakeMRFScore(ModelTreeType &model, InstanceTreeType &tree, NodeInstanceType &Instance)
{
	CAndNodeModel		&CurrModel	= model.AndModels[ModelID];
	int					ChildCount	= (int) children.size();
	vector<double>		geofeature;
	vector<double>		feature;
	double				Score;
	int					ret;

	Instance.ShapeScore = 0;
	Instance.AppearanceScore = Instance.NodeBaseAppearanceScore * CurrModel.AppearanceWeight;
	Instance.Score	= Instance.AppearanceScore;

	// Score of Children Nodes
	for ( int i = 0; i < ChildCount; i++ )
	{
		Instance.Score				+= tree.OrNodes[children[i]].instances[Instance.source[i]].Score;
		Instance.ShapeScore			+= tree.OrNodes[children[i]].instances[Instance.source[i]].ShapeScore;
		Instance.AppearanceScore	+= tree.OrNodes[children[i]].instances[Instance.source[i]].AppearanceScore;
	}

	// Score of Shape Model
	Score = 0;
	TripletScore_.clear();
	for ( int i = 0; i < (int) CurrModel.triplets.size(); i++ )
	{
		double	tripletScore;

		int	p1	= CurrModel.triplets[i].p1;
		int	p2	= CurrModel.triplets[i].p2;
		int	p3	= CurrModel.triplets[i].p3;

		if (CurrModel.triplets[i].m1 != Instance.ChildCenters[p1].OrIndex)
			continue;
		if (CurrModel.triplets[i].m2 != Instance.ChildCenters[p2].OrIndex)
			continue;
		if (CurrModel.triplets[i].m3 != Instance.ChildCenters[p3].OrIndex)
			continue;

		ret				= MakeTripletFeature(
			CurrModel.triplets[i], model,
			Instance.ChildCenters[p1], Instance.ChildCenters[p2], Instance.ChildCenters[p3],
			geofeature, Instance.center);
		tripletScore	= MakeTripletScore(model, i, geofeature);
		Score			+= CurrModel.triplets[i].gamma * tripletScore;
		TripletScore_.push_back(tripletScore);
	}
	Instance.Score		+= Score;
	Instance.ShapeScore	+= Score;

	// Score of Arc Model (Leaf Part)
	ArcRotScore_.assign(model.Rules.size(), 0);
	ArcScaleScore_.assign(model.Rules.size(), 0);
	for ( int t = 0; t < model.RuleStep; t++ )
	{
		if ((model.Rules[t].ArcType != 0) || (model.Rules[t].RootID != ModelID))
		{
			continue;
		}

		for ( int i = 0; i < ChildCount; i++ )
		{
			NodeInstanceType	&Inst1	= tree.OrNodes[children[i]].instances[Instance.source[i]];
			double				x1		= -1;
			double				y1		= -1;

			for ( int p = 0; p < (int) tree.OrNodes[children[i]].CenterIndex.size(); p++ )
			{
				if (tree.OrNodes[children[i]].CenterIndex[p] == model.Rules[t].LeafID1)
				{
					x1	= Inst1.Centers[p].x;
					y1	= Inst1.Centers[p].y;
				}
			}

			if ((x1 < 0) || (y1 < 0))
			{
				continue;
			}

			for ( int j = 0; j < ChildCount; j++ )
			{
				NodeInstanceType	&Inst2	= tree.OrNodes[children[j]].instances[Instance.source[j]];
				double				x2		= -1;
				double				y2		= -1;

				for ( int p = 0; p < (int) tree.OrNodes[children[j]].CenterIndex.size(); p++ )
				{
					if (tree.OrNodes[children[j]].CenterIndex[p] == model.Rules[t].LeafID2)
					{
						x2	= Inst2.Centers[p].x;
						y2	= Inst2.Centers[p].y;
					}
				}

				if ((x2 < 0) || (y2 < 0) || (i == j))
				{
					continue;
				}

				double	len		= __max(sqrt((x1-x2) * (x1-x2) + (y1-y2) * (y1-y2)), 1);
				double	dir		= (y2 > y1) ? (acos((x2-x1)/len)) : (-acos((x2-x1)/len));
				double	scale	= len / model.LeafLenInfo[model.Rules[t].LeafID1][model.Rules[t].LeafID2];
				double	rot		= OriDiff(model.LeafDirInfo[model.Rules[t].LeafID1][model.Rules[t].LeafID2], dir);
				double	SDiff	= scale - Instance.center.scale;
				double	RDiff	= OriDiff(Instance.center.ori, rot);

				Score			= 0;
				Score			-= model.Rules[t].ScaleWeight * SDiff * SDiff / (Variance * Variance);
				Score			-= model.Rules[t].RotWeight * RDiff * RDiff / (Variance * Variance);
				Instance.Score	+= Score;

				ArcScaleScore_[t]	-= SDiff * SDiff / (Variance * Variance);
				ArcRotScore_[t]		-= RDiff * RDiff / (Variance * Variance);
			}
		}
	}

	InstScore_ = Instance.Score;

	return	1;
}

int CAndNode::MakeInstanceLeafNodes(ModelTreeType &model, InstanceTreeType &tree, NodeInstanceType &Instance, vector<BasicNodePairType> &LeafNodes)
{
	CAndNodeModel	&CurrModel	= model.AndModels[ModelID];
	int				ChildCount	= (int) children.size();
	int				LeafCount	= (int) model.LeafModels.size();
	int				LeafID;

	LeafNodes.resize(LeafCount);
	for ( int i = 0; i < LeafCount; i++ )
	{
		LeafNodes[i].Missing	= 1;
		LeafNodes[i].FixCount	= 1;
	}

	for ( int i = 0; i < ChildCount; i++ )
	{
		if (Instance.source[i] >= 0)
		{
			NodeInstanceType	&SubInst	= tree.OrNodes[children[i]].instances[Instance.source[i]];
			for ( int j = 0; j < (int) SubInst.LeafNodeInfo.size(); j++ )
			{
				LeafID						= SubInst.LeafNodeInfo[j].LeafNodeIndex;
				LeafNodes[LeafID]			= SubInst.LeafNodeInfo[j];
				LeafNodes[LeafID].FixCount	= 0;
			}
		}
	}

	return	1;
}

int CAndNode::MakeInstanceLeafInfo(ModelTreeType &model, InstanceTreeType &tree, NodeInstanceType &Instance)
{
	CAndNodeModel				&CurrModel	= model.AndModels[ModelID];
	vector<BasicNodePairType>	LeafNodes;
	int							ChildCount	= (int) children.size();
	int							LeafCount	= (int) model.LeafModels.size();
	double						Rotate, Scale;
	int							LeafID, Count;

	LeafNodes.resize(LeafCount);
	for ( int i = 0; i < LeafCount; i++ )
	{
		LeafNodes[i].Missing	= 1;
		LeafNodes[i].FixCount	= 1;
	}
	for ( int i = 0; i < ChildCount; i++ )
	{
		NodeInstanceType	&SubInst	= tree.OrNodes[children[i]].instances[Instance.source[i]];

		for ( int j = 0; j < (int) SubInst.LeafNodeInfo.size(); j++ )
		{
			LeafID						= SubInst.LeafNodeInfo[j].LeafNodeIndex;
			LeafNodes[LeafID]			= SubInst.LeafNodeInfo[j];
			LeafNodes[LeafID].FixCount	= 0;
		}
	}

	Instance.LeafNodeInfo.clear();
	for ( int i = 0; i < LeafCount; i++ )
	{
		if (LeafNodes[i].FixCount == 0)
		{
			Instance.LeafNodeInfo.push_back(LeafNodes[i]);
		}
	}

	Count				= 0;
	Rotate				= Instance.center.ori;
	Scale				= Instance.center.scale;
	Instance.center.x	= 0;
	Instance.center.y	= 0;
	for ( int i = 0; i < (int) CurrModel.LeafCenterInfo.size(); i++ )
	{
		LeafID	= CurrModel.LeafCenterInfo[i].LeafID;

		if (LeafNodes[LeafID].FixCount == 0)
		{
			double	ori		= CurrModel.LeafCenterInfo[i].ori + M_PI;
			double	len		= CurrModel.LeafCenterInfo[i].len;
			double	x		= LeafNodes[LeafID].node.x;
			double	y		= LeafNodes[LeafID].node.y;

			Instance.center.x	+= x + Scale * len * cos(ori + Rotate);
			Instance.center.y	+= y + Scale * len * sin(ori + Rotate);
			Count++;
		}
	}
	Instance.center.x	/= Count;
	Instance.center.y	/= Count;

	return	1;
}

int CAndNode::MakeHierarchyInstanceCenter(NodeInstanceType &Instance)
{
	Instance.center.x	= 0;
	Instance.center.y	= 0;
	for ( int i = 0; i < (int) Instance.LeafNodeInfo.size(); i++ )
	{
		Instance.center.x	+= Instance.LeafNodeInfo[i].node.x;
		Instance.center.y	+= Instance.LeafNodeInfo[i].node.y;
	}

	Instance.center.x	/= (int) Instance.LeafNodeInfo.size();
	Instance.center.y	/= (int) Instance.LeafNodeInfo.size();
	return	1;
}

int	CAndNode::AddInstance_BottomUp(ModelTreeType &model, NodeInstanceType &Instance)
{
	CAndNodeModel	&CurrModel	= model.AndModels[ModelID];

	if ((ActiveThres == 1) && (Instance.Score < CurrModel.Threshold[model.RuleStep-1]))
	{
		return	1;
	}

	if (SearchConstrain.size() == 0)
	{
		fullInst.push_back(Instance);
	}
	
	if (SearchConstrain.size() > 0)
	{
		bool	ok	= false;

		for ( int i = 0; i < (int) SearchConstrain.size(); i++ )
		{
			if (InstanceSimilar(model, ModelID, SearchConstrain[i], Instance))
			{
				ok	= true;
				break;
			}
		}

		if (ok)
		{
			fullInst.push_back(Instance);
		}
	}

	return	1;
}

int	CAndNode::DrawInstance(ModelTreeType &model, CHiBoostImageEntity &entity, NodeInstanceType &instance, string strImageFileName)
{
	CImg<int> imgTemp;
	char strTemp[10001];
	int leaf_index;
	int ix, iy;
	int i, j;

	imgTemp = entity.CurrentImageLayer.imgScaled;
	for ( i = (int)imgTemp.size()-1; i >= 0; --i )
		imgTemp.data[i] = imgTemp.data[i]/2 + 128;
	for ( i = 0; i < (int) instance.LeafNodeInfo.size(); i++ )
	{
		leaf_index	= instance.LeafNodeInfo[i].LeafNodeIndex;
		ix = (int)instance.LeafNodeInfo[i].node.x;
		iy = (int)instance.LeafNodeInfo[i].node.y;
		for ( j = 0; j < (int)model.AndModels.size(); ++j )
			if (model.AndModels[j].LeafIndex == leaf_index) break;
		const Color& _color = g_Parameter.Colors[j % g_Parameter.Colors.size()];
		imgTemp.draw_circle(
			ix, iy, g_Parameter.PointRadiusForDrawing,
			CExternalTools::GetIntArrayRGB(_color.GetValue() & 0x00ffffff));
	}

	CImg<int> imgOutput;
	imgOutput.assign(imgTemp.width + 160, imgTemp.height, imgTemp.depth, imgTemp.dim);
	imgOutput.fill(255);
	imgOutput.draw_image(imgTemp, 0, 0);

	sprintf_s(strTemp, "Center: (%.1lf, %.1lf)", instance.center.x, instance.center.y);
	CExternalTools::OutputTextToImage(imgOutput, strTemp, imgTemp.width + 8, 8 + 0 * 20, 255, 255, 255, 255, 0, 0);
	sprintf_s(strTemp, "Rotate: %.1lf", instance.center.ori * 180 / M_PI);
	CExternalTools::OutputTextToImage(imgOutput, strTemp, imgTemp.width + 8, 8 + 1 * 20, 255, 255, 255, 255, 0, 0);
	sprintf_s(strTemp, "Scale : %.2lf", instance.center.scale);
	CExternalTools::OutputTextToImage(imgOutput, strTemp, imgTemp.width + 8, 8 + 2 * 20, 255, 255, 255, 255, 0, 0);
	sprintf_s(strTemp, "Score : %.6lf", instance.Score);
	CExternalTools::OutputTextToImage(imgOutput, strTemp, imgTemp.width + 8, 8 + 3 * 20, 255, 255, 255, 255, 0, 0);

	CExternalTools::mySaveImage(strImageFileName, imgOutput);

	////CImageEx			*pImage, *pOImage;
	////RGBQUAD				*pBits, *pRGB;
	////vector<Color>		colors	= g_Parameter.Colors;
	////int					LeafID;
	////int					ret;

	////// load pImage
	////pOImage	= new CImageEx();

	////CExternalTools::MakeCImageExInstance(*pOImage, entity.CurrentImageLayer.imgScaled);
	////////pOImage->Load(entity.strImageFileName.c_str());

	////pOImage->ConvertToARGB32Bits();
	////pBits	= (RGBQUAD*) pOImage->GetBits();

	////// Draw Background Image
	////pImage				= new CImageEx();
	////pImage->m_pBitmap	= new Bitmap(2 * entity.CurrentImageLayer.Scaled_W, entity.CurrentImageLayer.Scaled_H, PixelFormat32bppPARGB);
	////pRGB				= (RGBQUAD*) pImage->GetBits();
	////for ( int i = 0; i < entity.CurrentImageLayer.Scaled_H; i++ )
	////{
	////	for ( int j = 0; j < entity.CurrentImageLayer.Scaled_W; j++, pRGB++, pBits++ )
	////	{
	////		pRGB->rgbBlue		= pBits->rgbBlue;
	////		pRGB->rgbGreen		= pBits->rgbGreen;
	////		pRGB->rgbRed		= pBits->rgbRed;
	////		pRGB->rgbReserved	= pBits->rgbReserved;
	////	}
	////	for ( int j = 0; j < entity.CurrentImageLayer.Scaled_W; j++, pRGB++ )
	////	{
	////		pRGB->rgbBlue		= 255;
	////		pRGB->rgbGreen		= 255;
	////		pRGB->rgbRed		= 255;
	////		pRGB->rgbReserved	= 255;
	////	}
	////}
	////pImage->FreeBits();
	////pOImage->FreeBits();
	////pOImage->Unload();
	////delete	pOImage;

	////Graphics		graphics(pImage->m_pBitmap);
	////SolidBrush		myBrush(Color(0, 0, 0));
	////Font			myFont(L"Arial Narrow", 12, FontStyleBold);
	////Pen				myPen(&myBrush, 2);
	////wstring			strShowString;
	////char			szShowText[MAX_PATH];
	////PointF			point;

	////myPen.SetWidth(3);
	////for ( int i = 0; i < (int) instance.LeafNodeInfo.size(); i++ )
	////{
	////	LeafID	= instance.LeafNodeInfo[i].LeafNodeIndex;

	////	myBrush.SetColor(colors[LeafID % colors.size()]);
	////	myPen.SetColor(colors[LeafID % colors.size()]);

	////	point.X	= (float) instance.LeafNodeInfo[i].node.x;
	////	point.Y	= (float) instance.LeafNodeInfo[i].node.y;
	////	graphics.DrawEllipse(&myPen,   (int) (point.X - 3), (int) (point.Y - 3), (int) (2*3+1), (int) (2*3+1));
	////	graphics.FillEllipse(&myBrush, (int) (point.X - 3), (int) (point.Y - 3), (int) (2*3+1), (int) (2*3+1));
	////}

	////myPen.SetColor(Color(255, 0, 0));
	////myBrush.SetColor(Color(255, 0, 0));
	////sprintf_s(szShowText, MAX_PATH, "Center: (%.1f, %.1f)", instance.center.x, instance.center.y);
	////strShowString	= UTF82WChar( (const BYTE *)szShowText, (int) strlen(szShowText) );
	////point.X	= 0 + (Gdiplus::REAL)entity.CurrentImageLayer.Scaled_W;
	////point.Y	= 0;
	////graphics.DrawString(strShowString.c_str(), (int) strShowString.length(), &myFont, point, &myBrush);

	////myPen.SetColor(Color(255, 0, 0));
	////myBrush.SetColor(Color(255, 0, 0));
	////sprintf_s(szShowText, MAX_PATH, "Rotate: %.1f", instance.center.ori * 180 / M_PI);
	////strShowString	= UTF82WChar( (const BYTE *)szShowText, (int) strlen(szShowText) );
	////point.X	= 0 + (Gdiplus::REAL)entity.CurrentImageLayer.Scaled_W;
	////point.Y	= 20;
	////graphics.DrawString(strShowString.c_str(), (int) strShowString.length(), &myFont, point, &myBrush);

	////myPen.SetColor(Color(255, 0, 0));
	////myBrush.SetColor(Color(255, 0, 0));
	////sprintf_s(szShowText, MAX_PATH, "Scale : %.2f", instance.center.scale);
	////strShowString	= UTF82WChar( (const BYTE *)szShowText, (int) strlen(szShowText) );
	////point.X	= 0 + (Gdiplus::REAL)entity.CurrentImageLayer.Scaled_W;
	////point.Y	= 40;
	////graphics.DrawString(strShowString.c_str(), (int) strShowString.length(), &myFont, point, &myBrush);

	////myPen.SetColor(Color(255, 0, 0));
	////myBrush.SetColor(Color(255, 0, 0));
	////sprintf_s(szShowText, MAX_PATH, "Score : %.3f", instance.Score);
	////strShowString	= UTF82WChar( (const BYTE *)szShowText, (int) strlen(szShowText) );
	////point.X	= 0 + (Gdiplus::REAL)entity.CurrentImageLayer.Scaled_W;
	////point.Y	= 60;
	////graphics.DrawString(strShowString.c_str(), (int) strShowString.length(), &myFont, point, &myBrush);

	////// Save Image
	////ret	= pImage->Save(strImageFileName.c_str());
	////delete	pImage;

	return	1;
}

int CAndNode::ReCompositeAndNodeInst_MakeTree_NoEntity(ModelTreeType &model, InstanceTreeType &tree, int ChildID, NodeInstanceType &Instance)
{
	CAndNodeModel	&CurrModel	= model.AndModels[ModelID];
	int				ret;

	if ( ChildID >= (int) children.size() )
	{
		ret	= MakeInstanceRotateAndScaleByLeafNodes(model, tree, Instance);

		ret	= MakeMRFScore(model, tree, Instance);
		ret	= MakeInstanceLeafInfo(model, tree, Instance);
		ret	= MakeHierarchyInstanceCenter(Instance);
		ret	= AddInstanceArcCenters(model, Instance);
		instances.push_back(Instance);
	}
	else
	{
		vector<NodeInstanceType> &childInsts = tree.OrNodes[children[ChildID]].instances;
		for ( int i = 0; i < (int) childInsts.size(); i++ )
		{
			Instance.source[ChildID]		= i;
			Instance.ChildCenters[ChildID]	= childInsts[i].center;

			ret	= ReCompositeAndNodeInst_MakeTree_NoEntity(model, tree, ChildID + 1, Instance);
		}
	}

	return	1;
}

int CAndNode::CompositeAndNodeInst_MakeTree(ModelTreeType &model, InstanceTreeType &tree, CHiBoostImageEntity &entity, int ChildID, NodeInstanceType &Instance, bool fComputeAppearanceScore)
{
	CAndNodeModel	&CurrModel	= model.AndModels[ModelID];
	int				ret;

	if ( ChildID >= (int) children.size() )
	{
		ret	= MakeInstanceRotateAndScaleByLeafNodes(model, tree, Instance);

		//YUAN
		ret	= MakeInstanceLeafInfo(model, tree, Instance);
		if (fComputeAppearanceScore)
			MakeBaseAppearanceScore(entity, Instance);
		else
			Instance.NodeBaseAppearanceScore = 0.0;
		this->BaseAppearanceScore = Instance.NodeBaseAppearanceScore;
		ret	= MakeMRFScore(model, tree, Instance);

		//ret	= MakeMRFScore(model, tree, Instance);
		//ret	= MakeInstanceLeafInfo(model, tree, Instance);

		ret	= MakeHierarchyInstanceCenter(Instance);
		ret	= AddInstanceArcCenters(model, Instance);
		instances.push_back(Instance);
	}
	else
	{
		vector<NodeInstanceType> &childInsts = tree.OrNodes[children[ChildID]].instances;
		for ( int i = 0; i < (int) childInsts.size(); i++ )
		{
			Instance.source[ChildID]		= i;
			Instance.ChildCenters[ChildID]	= childInsts[i].center;

			ret	= CompositeAndNodeInst_MakeTree(model, tree, entity, ChildID + 1, Instance, fComputeAppearanceScore);
		}
	}

	return	1;
}

void CAndNode::RefreshMRFScore(ModelTreeType &model, InstanceTreeType& tree)
{
	if (!fNeedRefreshMRFScore) return;
	fNeedRefreshMRFScore = false;

	CAndNodeModel		&CurrModel	= model.AndModels[ModelID];
	int					ChildCount	= (int) CurrModel.Children.size();
	//NodeInstanceType	Instance;
	//int					ret;

	if (CurrModel.NodeType == 0)
	{
		for ( int i = 0; i < (int) instances.size(); i++ )
		{
			instances[i].ShapeScore = 0.0;
			instances[i].AppearanceScore = instances[i].NodeBaseAppearanceScore * CurrModel.AppearanceWeight;
			instances[i].Score = instances[i].ShapeScore + instances[i].AppearanceScore;
		}
		return;
	}

	NodeType	= 1;
	for ( int i = 0; i < ChildCount; i++ )
	{
		tree.OrNodes[children[i]].RefreshMRFScore(model, tree);
		//ret	= tree.OrNodes[children[i]].MakeInstTree(model, entity, tree, fComputeAppearanceScore);
	}

	for ( int i = 0; i < (int)instances.size(); i++ )
		MakeMRFScore(model, tree, instances[i]);

	//instances.clear();
	//Instance.source.resize(ChildCount);
	//Instance.ChildCenters.resize(ChildCount);
	//ret	= CompositeAndNodeInst_MakeTree(model, tree, entity, 0, Instance, fComputeAppearanceScore);
}

int CAndNode::RemakeInstTree_NoEntity(ModelTreeType &model, InstanceTreeType &tree)
{
	CAndNodeModel		&CurrModel	= model.AndModels[ModelID];
	int					ChildCount	= (int) CurrModel.Children.size();
	NodeInstanceType	Instance;
	int					ret;

	if (!fNeedMakeInstTree) return 1;
	fNeedMakeInstTree = false;

	if (CurrModel.NodeType == 0)
	{
		for ( int i = 0; i < (int) instances.size(); i++ )
		{
			ret	= AddInstanceArcCenters(model, instances[i]);
		}

		return	1;
	}

	NodeType	= 1;
	for ( int i = 0; i < ChildCount; i++ )
	{
		ret	= tree.OrNodes[children[i]].RemakeInstTree_NoEntity(model, tree);
	}

	instances.clear();
	Instance.source.resize(ChildCount);
	Instance.ChildCenters.resize(ChildCount);

	ret	= ReCompositeAndNodeInst_MakeTree_NoEntity(model, tree, 0, Instance);

	return	1;
}

int	CAndNode::MakeInstTree(ModelTreeType &model, CHiBoostImageEntity &entity, InstanceTreeType &tree, bool fComputeAppearanceScore)
{
	CAndNodeModel		&CurrModel	= model.AndModels[ModelID];
	int					ChildCount	= (int) CurrModel.Children.size();
	NodeInstanceType	Instance;
	int					ret;

	if (!fNeedMakeInstTree) return 1;
	fNeedMakeInstTree = false;

	if (CurrModel.NodeType == 0)
	{
		for ( int i = 0; i < (int) instances.size(); i++ )
		{
			ret	= AddInstanceArcCenters(model, instances[i]);
		}

		return	1;
	}

	NodeType	= 1;
	for ( int i = 0; i < ChildCount; i++ )
	{
		ret	= tree.OrNodes[children[i]].MakeInstTree(model, entity, tree, fComputeAppearanceScore);
	}

	instances.clear();
	Instance.source.resize(ChildCount);
	Instance.ChildCenters.resize(ChildCount);

	ret	= CompositeAndNodeInst_MakeTree(model, tree, entity, 0, Instance, fComputeAppearanceScore);

	return	1;
}

double CAndNode::AnalyseScore(
	vector<double>& DstScoreList_SubTree, vector<double>& DstScoreList_PerNode,
	CHiBoostImageEntity &entity, InstanceTreeType &tree, int InstID
	)
{
	NodeInstanceType	Instance	= instances[InstID];
	int i;

	DstScoreList_SubTree[ModelID] = DstScoreList_PerNode[ModelID] = Instance.Score;
	for ( i = 0; i < (int)children.size(); ++i )
		DstScoreList_PerNode[ModelID] -= tree.OrNodes[children[i]].AnalyseScore(DstScoreList_SubTree, DstScoreList_PerNode, entity, tree, Instance.source[i]);
	return DstScoreList_SubTree[ModelID];
}

int CAndNode::UpdateParameters(
	ModelTreeType &model, ModelTreeType &NewModel,
	CHiBoostImageEntity &entity,
	InstanceTreeType &tree, InstanceTreeType &ground_tree,
	int InstID,
	double UpdatingWeight)
{
	CAndNodeModel		&OldAndModel	= model.AndModels[ModelID];
	CAndNodeModel		&NewAndModel	= NewModel.AndModels[ModelID];
	CAndNode			&GroundNode	= ground_tree.AndNodes[ModelID];
	NodeInstanceType	Instance	= instances[InstID];
	int					ChildCount	= (int) children.size();
	vector<double>		feature1, feature2;
	int					ret;

	InstScore_	= Instance.Score;

	if (1)
	{
		NewAndModel.AppearanceWeight -= UpdatingWeight * (Instance.NodeBaseAppearanceScore - GroundNode.BaseAppearanceScore); 
	}

	if (OldAndModel.NodeType == 0)
	{
		////CLeafNodeModel	&LeafModel	= model.LeafModels[leafIndex];
		////CLeafNodeModel	&LeafModel_	= NewModel.LeafModels[leafIndex];

		////ret	= LeafModel.ConvertFeature(entity.nodes[Instance.source[0]].feature, LeafFeature_);
		////for ( int i = 0; i < (int) LeafModel.Weights.size(); i++ )
		////{
		////	LeafModel_.Weights[i]	-= UpdatingWeight * (LeafFeature_[i] - GroundNode.LeafFeature_[i]);
		////}

		return	1;
	}

	ret	= MakeMRFScore(model, tree, Instance);
	for ( int i = 0; i < (int) OldAndModel.triplets.size(); i++ )
	{
		NewAndModel.triplets[i].gamma	-= UpdatingWeight * (TripletScore_[i] - GroundNode.TripletScore_[i]);
	}

	for ( int i = 0; i < (int) model.Rules.size(); i++ )
	{
		NewModel.Rules[i].ScaleWeight	-= UpdatingWeight * (ArcScaleScore_[i] - GroundNode.ArcScaleScore_[i]);
		NewModel.Rules[i].RotWeight		-= UpdatingWeight * (ArcRotScore_[i] - GroundNode.ArcRotScore_[i]);
	}

	for ( int i = 0; i < ChildCount; i++ )
	{
		ret	= tree.OrNodes[children[i]].UpdateParameters(model, NewModel, entity, tree, ground_tree, Instance.source[i], UpdatingWeight);
	}

	//sprintf_s(filename, MAX_PATH, "%s\\%04d\\And-%04d-%04d.jpg", g_Parameter.strParseImagePathName.c_str(), entity.EntityID+1, ModelID, InstID);
	//ret	= DrawInstance(model, entity, instances[InstID], filename);

	return	1;
}

int CAndNode::AddSearchCenterIndex(ModelTreeType &model, InstanceTreeType &tree, ArcModelType &Rule, bool NxtStatus)
{
	CAndNodeModel	&CurrModel	= model.AndModels[ModelID];
	int				ChildCount	= (int) CurrModel.Children.size();
	bool			ok1, ok2;
	int				ret;

	for ( int i = 0; i < ChildCount; i++ )
	{
		ret	= tree.OrNodes[children[i]].AddSearchCenterIndex(model, tree, Rule, true);
	}

	if (NxtStatus == true)
	{
		ok1	= false;
		ok2	= false;
		for ( int i = 0; i < (int) CurrModel.MissLeafNode.size(); i++ )
		{
			ok1	= (CurrModel.MissLeafNode[i] != Rule.LeafID1) ? ok1 : true;
			ok2	= (CurrModel.MissLeafNode[i] != Rule.LeafID2) ? ok2 : true;
		}

		for ( int i = 0; i < (int) CenterIndex.size(); i++ )
		{
			ok1	= (CenterIndex[i] != Rule.LeafID1) ? ok1 : false;
			ok2	= (CenterIndex[i] != Rule.LeafID2) ? ok2 : false;
		}

		if (ok1)
		{
			CenterIndex.push_back(Rule.LeafID1);
			parseInfo	= false;
		}

		if (ok2)
		{
			CenterIndex.push_back(Rule.LeafID2);
			parseInfo	= false;
		}
	}

	return	1;
}

int CAndNode::SetNodeSearchStatus(ModelTreeType &model, InstanceTreeType &tree)
{
	CAndNodeModel	&CurrModel	= model.AndModels[ModelID];
	int				ChildCount	= (int) CurrModel.Children.size();
	int				ret;

	for ( int i = 0; i < ChildCount; i++ )
	{
		ret			= tree.OrNodes[children[i]].SetNodeSearchStatus(model, tree);
		parseInfo	= tree.AndNodes[children[i]].parseInfo ? parseInfo : false;
	}

	return	1;
}

int CAndNode::MakeMissLeafNodes(ModelTreeType &model, CHiBoostImageEntity &entity, InstanceTreeType &tree, BasicInstInfoType &center, vector<BasicNodePairType> &LeafNodes)
{
	CAndNodeModel				&CurrModel	= model.AndModels[ModelID];
	vector<BasicNodePairType>	CurrNodes;
	BasicNodePairType			LeafNode;
	double						cx		= center.x;
	double						cy		= center.y;
	double						scale	= center.scale;
	double						rotate	= center.ori;

	LeafNode.FixCount	= 0;
	LeafNode.Missing	= 1;
	CurrNodes.clear();
	if (NodeType == 0)
	{
		LeafNode.LeafNodeIndex	= leafIndex;
		LeafNode.node.x			= cx;
		LeafNode.node.y			= cy;
		if ((cx < 0) || (cx >= entity.CurrentImageLayer.Scaled_W) || (cy < 0) || (cy >= entity.CurrentImageLayer.Scaled_H))
		{
			return	1;
		}

		CurrNodes.push_back(LeafNode);
	}

	if (NodeType == 1)
	{
		for ( int i = 0; i < (int) CurrModel.LeafCenterInfo.size(); i++ )
		{
			LeafNode.LeafNodeIndex	= CurrModel.LeafCenterInfo[i].LeafID;
			LeafNode.node.x			= cx + scale * CurrModel.LeafCenterInfo[i].len * cos(rotate + CurrModel.LeafCenterInfo[i].ori);
			LeafNode.node.y			= cy + scale * CurrModel.LeafCenterInfo[i].len * sin(rotate + CurrModel.LeafCenterInfo[i].ori);
			if ((LeafNode.node.x < 0) || (LeafNode.node.x >= entity.CurrentImageLayer.Scaled_W) || (LeafNode.node.y < 0) || (LeafNode.node.y >= entity.CurrentImageLayer.Scaled_H))
			{
				return	1;
			}

			CurrNodes.push_back(LeafNode);
		}
	}

	LeafNodes.insert(LeafNodes.end(), CurrNodes.begin(), CurrNodes.end());
	return	1;
}

int CAndNode::MakeSearchConstrain(ModelTreeType &model, InstanceTreeType &tree, CHiBoostImageEntity &entity)
{
	int		ChildCount	= (int) children.size();
	int		InstID;
	int		ret;

	for ( int i = 0; i < (int) fullInst.size(); i++ )
	{
		if (ConstrainIndex[fullIndex[i]] == 1)
		{
			for ( int t = 0; t < ChildCount; t++ )
			{
				InstID	= fullInst[i].source[t];
				tree.OrNodes[children[t]].ConstrainIndex[InstID]	= 1;
			}
		}
	}

	SearchConstrain.clear();
	for ( int i = 0; i < (int) instances.size(); i++ ) 
	{
		if (ConstrainIndex[i] == 1)
		{
			SearchConstrain.push_back(instances[i]);
		}
	}

	for ( int t = 0; t < ChildCount; t++ )
	{
		ret	= tree.OrNodes[children[t]].MakeSearchConstrain(model, tree, entity);
	}

	return	1;
}

int	CAndNode::DrawSearchConstrains(ModelTreeType &model, CHiBoostImageEntity &entity, string strImageFileName)
{
	CImageEx			*pImage, *pOImage;
	RGBQUAD				*pBits, *pRGB;
	vector<Color>		Colors	= g_Parameter.Colors;
	int					Height, Width;
	int					ret;

	Height	= entity.CurrentImageLayer.Scaled_H;
	Width	= entity.CurrentImageLayer.Scaled_W;

	pOImage	= new CImageEx();

	CExternalTools::MakeCImageExInstance(*pOImage, entity.CurrentImageLayer.imgScaled);
	////pOImage->Load(entity.strImageFileName.c_str());

	pOImage->ConvertToARGB32Bits();
	pBits	= (RGBQUAD*) pOImage->GetBits();

	pImage				= new CImageEx();
	pImage->m_pBitmap	= new Bitmap(Width, Height, PixelFormat32bppPARGB);
	pRGB				= (RGBQUAD*) pImage->GetBits();

	for ( int i = 0; i < entity.CurrentImageLayer.Scaled_H; i++ )
	{
		for ( int j = 0; j < entity.CurrentImageLayer.Scaled_W; j++, pRGB++, pBits++ )
		{
			pRGB->rgbBlue		= pBits->rgbBlue / 2 + 128;
			pRGB->rgbGreen		= pBits->rgbGreen / 2 + 128;
			pRGB->rgbRed		= pBits->rgbRed / 2 + 128;
			pRGB->rgbReserved	= pBits->rgbReserved;
		}
	}
	pImage->FreeBits();
	pOImage->FreeBits();
	pOImage->Unload();
	delete	pOImage;

	Graphics		graphics(pImage->m_pBitmap);
	SolidBrush		myBrush(Color(0, 0, 0));
	Pen				myPen(&myBrush, 2);
	PointF			point;

	if (NodeType == 0)
	{
		myBrush.SetColor(Colors[leafIndex % Colors.size()]);
		myPen.SetColor(Colors[leafIndex % Colors.size()]);
	}
	else
	{
		myBrush.SetColor(Colors[ModelID % Colors.size()]);
		myPen.SetColor(Colors[ModelID % Colors.size()]);
	}

	for ( int i = 0; i < (int) SearchConstrain.size(); i++ )
	{
		point.X	= (float) SearchConstrain[i].center.x;
		point.Y	= (float) SearchConstrain[i].center.y;
		graphics.DrawEllipse(&myPen,   point.X - 1, point.Y - 1, 3.0f, 3.0f);
		graphics.FillEllipse(&myBrush, point.X - 1, point.Y - 1, 3.0f, 3.0f);
	}

	// Save Image
	ret	= pImage->Save(strImageFileName.c_str());
	delete	pImage;

	return	1;
}

void CAndNode::CreateNaiveModelFromNodes(ModelTreeType &model, InstanceTreeType &tree)
{
	string strModelImagePathName = "ModelDraw";

	CAndNodeModel				&CurrModel	= model.AndModels[ModelID];
	int							ChildCount	= (int)children.size();
	vector<BasicNodePairType>	LeafNodes_;
	NodeInstanceType			Instance;

	if (createInfo) return;

	// Initialize Appearance Weight
	CurrModel.AppearanceWeight = 1.0;

	if (CurrModel.LeafIndex >= 0)
	{
		CurrModel.NodeType	= 0;
		CurrModel.Children.clear();

		//YUAN
		CurrModel.ModelCount = 0;

		instances.resize(1);
		instances[0].ChildCenters.clear();
		instances[0].LeafNodeInfo.resize(1);
		instances[0].source.resize(1);
		instances[0].center.x			= 0.0; // LeafNodes[CurrModel.LeafIndex].x;
		instances[0].center.y			= 0.0; // LeafNodes[CurrModel.LeafIndex].y;
		instances[0].center.ori			= 0.0; // 0;
		instances[0].center.scale		= 1.0; // -1;
		instances[0].center.OrIndex = -1;
		instances[0].LeafNodeInfo[0].LeafNodeIndex	= CurrModel.LeafIndex;
		instances[0].LeafNodeInfo[0].FixCount		= 1;
		instances[0].LeafNodeInfo[0].Missing		= 0;

		instances[0].LeafNodeInfo[0].node.x = 0.0;
		instances[0].LeafNodeInfo[0].node.y = 0.0;
		instances[0].LeafNodeInfo[0].node.ori = 0.0;
		//instances[0].LeafNodeInfo[0].node			= LeafNodes[CurrModel.LeafIndex];

		instances[0].Score		= 0;
		instances[0].ShapeScore = 0;
		instances[0].AppearanceScore = 0;
		instances[0].NodeBaseAppearanceScore = 0;
		instances[0].source[0]	= 0;

		//for ( int i = 0; i < (int) instances.size(); i++ )
		//{
		//	char	filename[MAX_PATH];
		//	sprintf_s(filename, MAX_PATH, "%s\\%03d-%03d.jpg", strModelImagePathName.c_str(), ModelID, i);
		//	ret	= DrawModelInstance(model, instances[i], LeafNodes, filename);
		//}

		createInfo	= true;
		return;
	}

	CurrModel.NodeType	= 1;
	for ( int i = 0; i < ChildCount; i++ )
	{
		tree.OrNodes[children[i]].CreateNaiveModelFromNodes(model, tree);
	}

	CurrModel.ModelCount	= 0;
	CurrModel.NodeModelIndex.resize(ChildCount);
	for ( int i = 0; i < ChildCount; i++ )
	{
		CurrModel.NodeModelIndex[i]	= CurrModel.ModelCount;
		CurrModel.ModelCount		+= model.OrModels[children[i]].ModelCount;
	}

	Instance.source.resize(ChildCount);
	Instance.ChildCenters.resize(ChildCount);
	LeafNodes_.resize(model.LeafModels.size());
	for ( int i = 0; i < (int) model.LeafModels.size(); i++ )
	{
		LeafNodes_[i].LeafNodeIndex	= i;
		LeafNodes_[i].FixCount		= -1;
		LeafNodes_[i].Missing		= -1;
	}
	CreateAndNodeInstance(model, tree, 0, Instance, LeafNodes_);

	CreateUpdateAndNodeModel(model, tree);

	//// Draw Model Images
	//for ( int i = 0; i < (int) instances.size(); i++ )
	//{
	//	char	filename[MAX_PATH];

	//	sprintf_s(filename, MAX_PATH, "%s\\%03d-%03d.jpg", strModelImagePathName.c_str(), ModelID, i);
	//	ret	= DrawModelInstance(model, instances[i], LeafNodes, filename);
	//}

	//if (ModelID == 0)																// Level == 0 or OrNode[tree.Root]
	//{
	//	for ( int i = 0; i < (int) instances.size(); i++ )
	//	{
	//		char	filename[MAX_PATH];

	//		sprintf_s(filename, MAX_PATH, "%s\\template\\template%03d.jpg", strModelImagePathName.c_str(), i);
	//		ret	= DrawModelInstance(model, instances[i], LeafNodes, filename);
	//		sprintf_s(filename, MAX_PATH, "%s\\template\\template%03d.txt", strModelImagePathName.c_str(), i);
	//		ret	= PrintModelTemplate(model, instances[i], i, filename);
	//	}
	//}

	createInfo	= true;
}

void CAndNode::_MergeChildInstance_BottomUp(NodeInstanceType &Instance, vector<BasicNodePairType> &LeafNodes, int ChildID)
{
	for ( int i = 0; i < (int) Instance.LeafNodeInfo.size(); i++ )
	{
		int	LeafID	= Instance.LeafNodeInfo[i].LeafNodeIndex;
		if (LeafNodes[LeafID].FixCount < 0)
		{
			LeafNodes[LeafID]			= Instance.LeafNodeInfo[i];
			LeafNodes[LeafID].FixCount	= ChildID;
		}
	}
}

void CAndNode::_RemoveChildInstance_BottomUp(vector<BasicNodePairType> &LeafNodes, int ChildID)
{
	for ( int i = 0; i < (int) LeafNodes.size(); i++ )
	{
		if (LeafNodes[i].FixCount == ChildID)
		{
			LeafNodes[i].FixCount	= -1;
		}
	}
}

void CAndNode::CreateAndNodeInstance(ModelTreeType &model, InstanceTreeType &tree, int ChildID, NodeInstanceType &instance, vector<BasicNodePairType> &LeafNodes)
{
	CAndNodeModel	&CurrModel	= model.AndModels[ModelID];
	int				ChildCount	= (int) children.size();

	if (ChildID >= ChildCount)
	{
		CreateUpdateAndNodeInstance(model, tree, instance, LeafNodes);
	}
	else
	{
		vector<NodeInstanceType> &childInsts = tree.OrNodes[children[ChildID]].instances;
		for ( int i = 0; i < (int) childInsts.size(); i++ )
		{
			instance.source[ChildID]		= i;
			instance.ChildCenters[ChildID]	= childInsts[i].center;

			_MergeChildInstance_BottomUp(childInsts[i], LeafNodes, ChildID);
			CreateAndNodeInstance(model, tree, ChildID + 1, instance, LeafNodes);
			_RemoveChildInstance_BottomUp(LeafNodes, ChildID);
		}
	}
}

void CAndNode::CreateUpdateAndNodeInstance(ModelTreeType &model, InstanceTreeType &tree, NodeInstanceType &instance, vector<BasicNodePairType> &LeafNodes)
{
	CAndNodeModel	&CurrModel	= model.AndModels[ModelID];
	int				ChildCount	= (int) children.size();

	instance.center.x		= 0;
	instance.center.y		= 0;
	instance.center.ori		= 0;
	instance.center.scale	= 1.0;
	for ( int i = 0; i < (int) instance.ChildCenters.size(); i++ )
	{
		instance.center.x	+= instance.ChildCenters[i].x;
		instance.center.y	+= instance.ChildCenters[i].y;
	}
	instance.center.x	/= (int) instance.ChildCenters.size();
	instance.center.y	/= (int) instance.ChildCenters.size();

	instance.LeafNodeInfo.clear();
	for ( int i = 0; i < (int) LeafNodes.size(); i++ )
	{
		if (LeafNodes[i].FixCount >= 0)
		{
			instance.LeafNodeInfo.push_back(LeafNodes[i]);
		}
	}

	instances.push_back(instance);
}

void CAndNode::CreateUpdateAndNodeModel(ModelTreeType &model, InstanceTreeType &tree)
{
	CAndNodeModel		&CurrModel	= model.AndModels[ModelID];
	int					ChildCount	= (int) children.size();
	int					LeafCount	= (int) model.LeafModels.size();
	double				centerx, centery;
	int					count;
	//int					ret;

	// update the center of instances
	centerx	= 0;
	centery	= 0;
	count	= 0;
	for ( int i = 0; i < (int) instances.size(); i++ )
	{
		centerx	+= instances[i].center.x;
		centery	+= instances[i].center.y;
		count++;
	}
	centerx	/= count;
	centery	/= count;

	for ( int i = 0; i < (int) instances.size(); i++ )
	{
		instances[i].center.x	= centerx;
		instances[i].center.y	= centery;
	}

	// NodeLenInfo, NodeOriInfo
	CurrModel.NodeLenInfo.alloc(CurrModel.ModelCount, CurrModel.ModelCount);
	CurrModel.NodeDirInfo.alloc(CurrModel.ModelCount, CurrModel.ModelCount);
	for ( int i = 0; i < (int) instances.size(); i++ )
	{
		for ( int j = 0; j < (int) instances[i].ChildCenters.size(); j++ )
		{
			for ( int k = 0; k < (int) instances[i].ChildCenters.size(); k++ )
			{
				if (j == k)	continue;

				int	MID1	= CurrModel.NodeModelIndex[j] + instances[i].ChildCenters[j].OrIndex;
				int	MID2	= CurrModel.NodeModelIndex[k] + instances[i].ChildCenters[k].OrIndex;

				double	x1	= instances[i].ChildCenters[j].x;
				double	y1	= instances[i].ChildCenters[j].y;
				double	x2	= instances[i].ChildCenters[k].x;
				double	y2	= instances[i].ChildCenters[k].y;

				double	len	= __max(sqrt((x1-x2) * (x1-x2) + (y1-y2) * (y1-y2)), 1);
				double	ori	= 0.0; // (y2 > y1) ? (acos((x2-x1) / len)) : (-acos((x2-x1) / len));

				CurrModel.NodeLenInfo[MID1][MID2]	= len;
				CurrModel.NodeDirInfo[MID1][MID2]	= ori;
			}
		}
	}
	// End

	// LeafCenterInfo
	vector<double>		leafCenterLen(LeafCount, 0);
	vector<double>		leafCenterOri(LeafCount, 0);
	vector<int>			leafCenterIndex(LeafCount, -1);

	count	= 0;
	for ( int i = 0; i < (int) instances.size(); i++ )
	{
		for ( int j = 0; j < (int) instances[i].LeafNodeInfo.size(); j++ )
		{
			int		LeafID	= instances[i].LeafNodeInfo[j].LeafNodeIndex;
			double	x1		= instances[i].center.x;
			double	y1		= instances[i].center.y;
			double	x2		= instances[i].LeafNodeInfo[j].node.x;
			double	y2		= instances[i].LeafNodeInfo[j].node.y;
			double	len		= __max(sqrt((x1-x2) * (x1-x2) + (y1-y2) * (y1-y2)), 1);
			double	ori		= 0.0; // (y2 > y1) ? (acos((x2-x1) / len)) : (-acos((x2-x1) / len));

			if (leafCenterIndex[LeafID] < 0)	count++;
			leafCenterIndex[LeafID]	= 1;
			leafCenterLen[LeafID]	= len;
			leafCenterOri[LeafID]	= ori;
		}
	}

	CurrModel.LeafCenterInfo.resize(count);
	count	= 0;
	for ( int i = 0; i < LeafCount; i++ )
	{
		if (leafCenterIndex[i] < 0)	continue;

		CurrModel.LeafCenterInfo[count].LeafID	= i;
		CurrModel.LeafCenterInfo[count].len		= leafCenterLen[i];
		CurrModel.LeafCenterInfo[count].ori		= leafCenterOri[i];
		count++;
	}
	// End

	// triplets
	CurrModel.triplets.clear();
	for ( int i = 0; i < (int) instances.size(); i++ )
	{
		for ( int j = 0; j < ChildCount - 2; j++ )
		{
			CAndNodeModel::TripletType		triplet;
			bool							ok;

			triplet.p1	= j;
			triplet.p2	= j + 1;
			triplet.p3	= j + 2;
			triplet.m1	= instances[i].ChildCenters[j].OrIndex;
			triplet.m2	= instances[i].ChildCenters[j+1].OrIndex;
			triplet.m3	= instances[i].ChildCenters[j+2].OrIndex;

			ok	= true;
			for ( int t = 0; t < (int) CurrModel.triplets.size(); t++ )
			{
				if ( (triplet.p1 != CurrModel.triplets[t].p1) || (triplet.p2 != CurrModel.triplets[t].p2) || (triplet.p3 != CurrModel.triplets[t].p3) )
					continue;
				if ( (triplet.m1 != CurrModel.triplets[t].m1) || (triplet.m2 != CurrModel.triplets[t].m2) || (triplet.m3 != CurrModel.triplets[t].m3) )
					continue;

				ok	= false;
				break;
			}

			if ( !ok )	continue;

			triplet.feature.assign(12, 0.0);
			triplet.variance.assign(12, 0.12);
			triplet.gamma = 1.0;
			//ret	= makeTripletFeature(instances[i].ChildCenters[j], instances[i].ChildCenters[j+1], instances[i].ChildCenters[j+2], triplet.feature, instances[i].center);
			//triplet.variance.assign(12, g_Parameter.m_fTriplerVariance);
			//triplet.gamma	= g_Parameter.m_fTripletGamma;

			//double	gamma	= (1 - g_Parameter.m_fAndChildWeight) / (ChildCount - 2);
			//triplet.gamma	= gamma;

			if (instances[i].ChildCenters[j].scale < 0)
			{
				triplet.variance[9]		= 0;
				triplet.variance[10]	= 0;
				triplet.variance[11]	= 0;
			}

			CurrModel.triplets.push_back(triplet);
		}
	}
	// End
}

